package xq.gwt.mvc.model;

import java.io.Serializable;
import java.util.ArrayList;

public abstract class AbstractPropertyModel implements PropertyModel, Serializable{
	private static final long serialVersionUID = -8083965268144885035L;
	protected String title;
	protected String name;
	transient protected ArrayList<PropertyChangedListener> listeners = new ArrayList<PropertyChangedListener>();
	transient protected ArrayList<ReadOnlyChangedListener> readOnlyListeners = new ArrayList<ReadOnlyChangedListener>();
	transient protected ArrayList<RequiredChangedListener> requiredListeners = new ArrayList<RequiredChangedListener>();
	protected boolean required;
	protected ListItem[] valueItems;
	protected boolean hasError;
	protected boolean readonly;
	protected boolean hidden;
	protected boolean isNotPersistent;
	protected boolean limitToList;
	transient protected PropertyRelation relation;
	
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
			
	public boolean isRequired() {
		return required;
	}
	public void setRequired(boolean required) {
		this.required = required;
		notifyRequiredChanged();
	}
			
	public ListItem[] getValueItems() {
		return valueItems;
	}
	public void setValueItems(ListItem[] valueItems) {
		this.valueItems = valueItems;
	}
	protected void notifyPropertyChanged(Object oldValue, Object newValue){
		if(oldValue == newValue)
			return;
		if((oldValue == null) && (newValue == null))
			return;
		if(oldValue != null){
			if(oldValue.equals(newValue))
				return;
		}
			
		for (int i = 0; i < listeners.size(); i++) {
			PropertyChangedListener listener = listeners.get(i);
			if (listener != null){
				PropertyChangedEvent event = new PropertyChangedEvent();
				event.setNewValue(newValue);
				event.setOldValue(oldValue);
				event.setSource(this);
				listener.propertyChanged(event);
			}
				
		}
		 
	}
	
	protected void notifyReadonlyChanged(){
		for (int i = 0; i < readOnlyListeners.size(); i++) {
			ReadOnlyChangedListener listener = readOnlyListeners.get(i);
			if(listener != null)
				listener.readOnlyChanged();
		}
	}
	
	protected void notifyRequiredChanged(){
		for (int i = 0; i < requiredListeners.size(); i++) {
			RequiredChangedListener listener = requiredListeners.get(i);
			if(listener != null)
				listener.requiredChanged();
		}
	}
	
	public void addPropertyChangedListener(PropertyChangedListener listener){
		if(listener == null)
			return;
		if(!listeners.contains(listener))
			listeners.add(listener);
	}
	
	public void removePropertyChangedListener(PropertyChangedListener listener){
		listeners.remove(listener);
	}
	
	public void addReadOnlyChangedListener(ReadOnlyChangedListener listener){
		if(listener == null)
			return;
		if(!readOnlyListeners.contains(listener))
			readOnlyListeners.add(listener);
	}
	
	public void removeReadOnlyChangedListener(ReadOnlyChangedListener listener){		
		readOnlyListeners.remove(listener);
	}
	
	public void addRequiredChangedListener(RequiredChangedListener listener){
		if(listener == null)
			return;
		if(!requiredListeners.contains(listener))
			requiredListeners.add(listener);
	}
	
	public void removeRequiredChangedListener(RequiredChangedListener listener){		
		requiredListeners.remove(listener);
	}
	
	public void removeAllPropertyChangedListeners(){
		listeners.clear();
		readOnlyListeners.clear();
		requiredListeners.clear();
	}
	
	
	
	public boolean isValid(){
		if (getHasError())
			return false;
		if((isRequired()) && (getText() == null))
			return false;
		if((isRequired()) && (getText().equals("")))
			return false;		
		return true;
	}
	
	private boolean valueInList(){		
		if(valueItems == null){
			return true;
		}
		
		if((getText() == null) || ("".equals(getText()))){
			return true;
		}
		
		for (int i = 0; i < valueItems.length; i++) {
			try {
				if(valueItems[i].value.equals(getText())){
					return true;
				}
			} catch (Exception e) {}
			
		}
		return false;
	}
	
	public boolean getHasError() {
		if(hasError)
			return true;		
		if(isLimitToList()){
			return !valueInList();
		}
		return hasError;
	}
	public void setHasError(boolean hasError) {
		this.hasError = hasError;
	}
	
	
	
	public boolean isReadonly() {
		return readonly;
	}
	public void setReadonly(boolean readonly) {
		this.readonly = readonly;
		notifyReadonlyChanged();
	}
		
	public boolean isHidden() {
		return hidden;
	}
	public void setHidden(boolean hidden) {
		this.hidden = hidden;
	}
	
	
	
	@Override
	public boolean isNotPersistent() {
		return isNotPersistent;
		
	}
	@Override
	public void setNotPersistent(boolean isNotPersistent) {
		this.isNotPersistent = isNotPersistent;
		
	}
	
	
	
	@Override
	public boolean isLimitToList() {		
		return limitToList;
	}
	@Override
	public void setLimitToList(boolean value) {
		limitToList = value;
		
	}
		
	@Override
	public PropertyRelation getRelation() {		
		return relation;
	}
	@Override
	public void setRelation(PropertyRelation relation) {
		this.relation = relation;		
	}
	
	public abstract String getText();
	public abstract void setText(String text) throws ConversionException;
}
